package org.istt.web;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.istt.domain.Department;
import org.istt.domain.Group;
import org.istt.domain.Position;
import org.istt.domain.User;
import org.istt.service.DepartmentManager;
import org.istt.service.GroupManager;
import org.istt.service.PositionManager;
import org.istt.service.UserManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.encoding.PasswordEncoder;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;





public class UserAction extends ActionSupport {
    /**
	 * 
	 */
	private static final long serialVersionUID = 7993280077731267937L;
	private List<String> addedlstgroups = new ArrayList<String>();
    private String cancel;
    private String confirmPassword;
    private String delete;
    
    private String departmentId; 
    private DepartmentManager departmentManager;
	private Group group;
    private String groupId;
    private GroupManager groupMgr;
    private Set<Group> groups ;
    private String id;
    private List<Department> listDepartment;
    private List<Group> listGrp;
    private final Log log = LogFactory.getLog(UserAction.class);
	private List<String> lstgroups = new ArrayList<String>();
    private UserManager mgr;
	private List<String> newlstgroups = new ArrayList<String>();
    private String password;
    private PasswordEncoder passwordEncoder;
    private String positionId;
    private PositionManager positionManager;
    private String search;
    private User user;
    
    
    private List<User> users;
    
    public String delete() {
        if (log.isDebugEnabled()) {
            log.debug("entering 'delete' method");
        }		
        if (mgr.searchUserToDelete(user.getId())) {
	        mgr.remove(user.getId());
	        ActionContext.getContext().getSession().put("message", getText("user.deleted"));
        } else
    		ActionContext.getContext().getSession()
			.put("message", getText("user.deleted.error"));
        return "delete";
    }

	public String edit() {		
        //System.out.println(lstgroups);
        // check for an add
        if (id != null) {
        	user = mgr.get(NumberUtils.toLong(id));
        	groups = user.getGroups();
        	List<Group> lstGroup2 = new ArrayList<Group>(groups);

            for (int i = 0; i < groups.size(); i++) {
            	group = lstGroup2.get(i);
                addedlstgroups.add(String.valueOf(group.getId()));
            }

            
        } else {
        	user = new User();
        }        
        return SUCCESS;
    }

	public String updateInfo() {		
		// check for an add
		if (id != null) {
			User loggedUser = (User)ActionContext.getContext().getSession().get(WebConstants.USER_INFO);
			
			if(loggedUser.getId() == NumberUtils.toLong(id)){
				user = mgr.get(NumberUtils.toLong(id));
			}else{
				ActionContext.getContext().getSession().put("error", getText("general.error.access.denied"));
				
				return ERROR;
			}
        }else{
        	
        	ActionContext.getContext().getSession().put("error", getText("general.error.access.denied"));
        	return ERROR;
        }
		return SUCCESS;
	}
	
	public String execute() {
        if (cancel != null) {
            return "cancel";
        }
        if (delete != null) {
            return delete();
        }
        if (search != null) {
        	return search();
        }
        
        return SUCCESS;
    }
	
	public List<String> getAddedlstgroups() {
		return addedlstgroups;
	}


	public String getCancel() {
		return cancel;
	}

	public String getConfirmPassword() {
		return confirmPassword;
	}


    public String getDelete() {
		return delete;
	}

	public String getDepartmentId() {
		if (user != null) {
			departmentId = user.getDepartment() == null ? departmentId : user.getDepartment().getId() + "";
		}
		return departmentId;
	}
	
    public List<Department> getDepartments() {
		return departmentManager.getList();
	}



    public Group getGroup() {
		return group;
	}

	public String getGroupId() {
		return groupId;
	}    
    
    
    public GroupManager getGroupMgr() {
		return groupMgr;
	}
    
    public Set<Group> getGroups() {
		return groups;
	}
    
    public String getId() {
		return id;
	}

	public List<Department> getListDepartment() {
		return this.departmentManager.getList();
	}

	public List<Group> getListGrp() {
		List<Group> lstGroups = groupMgr.getList();
		List<Group> results = new ArrayList<Group>();
    	for (Iterator<Group> iterator = lstGroups.iterator(); iterator.hasNext();) {
			Group grp = (Group) iterator.next();
			if(grp.getRoleSystem() && grp.getAuthority().equals("ROLE_USER")){
				//TODO: do not add to list
			}else{
				results.add(grp);
			}
		}
		return results;
	}

	public List<Group> getLstGroup() {
		List<Group> lstGroups = groupMgr.getList();
		List<Group> results = new ArrayList<Group>();
    	for (Iterator<Group> iterator = lstGroups.iterator(); iterator.hasNext();) {
			Group grp = (Group) iterator.next();
			if(grp.getRoleSystem() && grp.getAuthority().equals("ROLE_USER")){
				//TODO: do not add to list
			}else{
				results.add(grp);
			}
		}
		return results;
	}

    public List<String> getLstgroups() {
		return lstgroups;
	}

	public UserManager getMgr() {
		return mgr;
	}
	
    public List<String> getNewlstgroups() {
		return newlstgroups;
	}

	public String getPassword() {
		return password;
	}

	public String getPositionId() {
		if (user != null) {
			positionId = user.getPosition() == null ? positionId : user.getPosition().getId() + "";
		}
		return positionId;
	}
    


	public List<Position> getPositions() {
		return positionManager.getList();
	}

	public String getSearch() {
		return search;
	}

    public User getUser() {
		return user;
	}

    public String getUserByDepartment(){
		log.debug("Dept ID = "+this.departmentId);
		if(this.departmentId!=null && !"".equals(this.departmentId)){
			this.users = new ArrayList<User>(this.mgr.findUserByDeptId(Long.parseLong(this.departmentId)));
		}else{
			Department dept = (Department)this.departmentManager.getList().get(0);
			this.departmentId = dept.getId()+"";
			this.users = new ArrayList<User>(dept.getUsers());
		}
		return SUCCESS;
	}



	public String getUserByGroup(){
		log.debug("Group ID = "+this.groupId);
		if(this.groupId!=null && !"".equals(this.groupId)){
			this.group = this.groupMgr.get(Long.parseLong(this.groupId));
			if(this.group!=null) this.users = new ArrayList<User>(this.group.getUsers());
		}else{
			this.group = this.groupMgr.getList().get(0);
			this.groupId = this.group.getId().toString();
			if(this.group!=null) this.users = new ArrayList<User>(this.group.getUsers());
		}
		return SUCCESS;
	}

	public List<User> getUsers() {
		return users;
	}

	public String list() { 
    	users = mgr.getList();
        return SUCCESS; 
    }

	public String loadSearch() {
        if (log.isDebugEnabled()) {
            log.debug("entering 'load search' method");
        }		
		return SUCCESS;
	}

	public String save() {
        if (log.isDebugEnabled()) {
            log.debug("entering 'save' method");
        }
        
        if (user.getId() != null) {
        	//update user
        	String oldPwd = mgr.get(user.getId()).getPassword();
            if (!password.equals("******")) {
            	user.setPassword(passwordEncoder.encodePassword(password, null));
            }
            else {
    	        user.setPassword(oldPwd);
            }
            user.setDateModified(new Date());
            user.setGroups(null);
        	Set<Group> g = new HashSet<Group>();
        	for (int i = 0; i < newlstgroups.size(); i++) {
            	group=groupMgr.get(NumberUtils.toLong(newlstgroups.get(i).trim()));
            	g.add(group);
            	//TODO: checking the selected group is admin group
            	// If it's admin group, auto assign user to SYSUSER group
				// ROLE_ADMINISTRATOR
            	if(group.getAuthority().equals(WebConstants.ROLE_ADMINISTRATOR)){
            		//Asign user to Role_user
            		Group sysUserGroup = groupMgr.getGroup(WebConstants.ROLE_USER, true);
            		g.add(sysUserGroup);
            		
            		//Asign user to Role_moderator
            		Group sysModeratorGroup = groupMgr.getGroup(WebConstants.ROLE_MODERATOR, true);
            		g.add(sysModeratorGroup);
            	}
				// ROLE_MODERATOR
            	if(group.getAuthority().equals(WebConstants.ROLE_MODERATOR)){
            		
            		//Asign user to Role_user
            		Group sysUserGroup = groupMgr.getGroup(WebConstants.ROLE_USER, true);
            		g.add(sysUserGroup);
            	}
            }
        	
        	user.setGroups(g);
            
        	Department depObj = departmentManager.get(Long.parseLong(this.departmentId));
        	
        	user.setDepartment(depObj);
            
        	Position posObj = positionManager.get(Long.parseLong(this.positionId));
        	
        	user.setPosition(posObj);
        	mgr.save(user);
        	
        } else {
        	//create new user;
        	user.setPassword(passwordEncoder.encodePassword(password, null));
        	user.setDateCreated(new Date());
        	
        	Set<Group> g = user.getGroups();
            for (int i = 0; i < newlstgroups.size(); i++) {
            	group=groupMgr.get(NumberUtils.toLong(newlstgroups.get(i).trim()));
            	g.add(group);
            	
            	//TODO: checking the selected group is admin group
            	// If it's admin group, auto assign user to SYSUSER group
            	if(group.getAuthority().equals(WebConstants.ROLE_ADMINISTRATOR)){
            		// Get User group
            		Group sysUserGroup = groupMgr.getGroup(WebConstants.ROLE_USER, true);
            		g.add(sysUserGroup);
            		
            		//Asign user to Role_moderator
            		/*Group sysModeratorGroup = groupMgr.getGroup(WebConstants.ROLE_MODERATOR, true);
            		g.add(sysModeratorGroup);*/
            	}
            	
            	// ROLE_MODERATOR
            	if(group.getAuthority().equals(WebConstants.ROLE_MODERATOR)){
            		
            		//Asign user to Role_user
            		Group sysUserGroup = groupMgr.getGroup(WebConstants.ROLE_USER, true);
            		g.add(sysUserGroup);
            	}
            }
            user.setGroups(g);
            
        	Department depObj = departmentManager.get(Long.parseLong(this.departmentId));
        	
        	user.setDepartment(depObj);
            
        	Position posObj = positionManager.get(Long.parseLong(this.positionId));
        	
        	user.setPosition(posObj);
        	user.setEnabled(true);//TODO: modified enable user
        	
            mgr.save(user);
        }
        
        ActionContext.getContext().getSession().put("message", getText("user.saved"));
                
        return SUCCESS;
    }
	
	
	public String saveInfo() {
		if (log.isDebugEnabled()) {
			log.debug("entering 'saveInfo' method");
		}
		
		if (user.getId() != null) {
			//Get original user
			User tmpUser = mgr.get(user.getId());
			
			String oldPwd = tmpUser.getPassword();
			
			// Update new password
			if (!password.equals("******")) {
				user.setPassword(passwordEncoder.encodePassword(password, null));
			}
			else {
				user.setPassword(oldPwd);
			}
			
			user.setDateModified(new Date());
			user.setGroups(tmpUser.getGroups());
			user.setDepartment(tmpUser.getDepartment());
			user.setPosition(tmpUser.getPosition());
			
			//execute save user
			mgr.save(user);
			
			//Update user session
			Map session = ActionContext.getContext().getSession();
			session.put(WebConstants.USER_INFO, user);
			
		}
		
		ActionContext.getContext().getSession().put("message", getText("user.saved"));
		
		return SUCCESS;
	}

    
	public String search() {
        if (log.isDebugEnabled()) {
            log.debug("entering 'search' method");
        }		
		if(user!=null && (!"".equals(user.getUsername()) || !"".equals(user.getFirstName()) || !"".equals(user.getLastName()) || !"0".equals(departmentId) || !"0".equals(positionId)))  {
			//setUsers(this.mgr.search(user));
			setUsers(this.mgr.searchUser(user.getUsername(), user.getLastName(), user.getFirstName(), NumberUtils.toLong(departmentId), NumberUtils.toLong(positionId)));
		}
		
		return SUCCESS;
	}

	public void setAddedlstgroups(List<String> addedlstgroups) {
		this.addedlstgroups = addedlstgroups;
	}
    
    
	public void setCancel(String cancel) {
        this.cancel = cancel;
    }

	public void setConfirmPassword(String confirmPassword) {
		this.confirmPassword = confirmPassword;
	}

	public void setDelete(String delete) {
        this.delete = delete;
    }

	public void setDepartmentId(String departmentId) {
		this.departmentId = departmentId;
	}

	@Autowired
	public void setDepartmentManager(DepartmentManager departmentManager) {
		this.departmentManager = departmentManager;
	}

	public void setGroup(Group group) {
		this.group = group;
	}

	public void setGroupId(String groupId) {
		this.groupId = groupId;
	}

	public void setGroupMgr(GroupManager groupMgr) {
		this.groupMgr = groupMgr;
	}
    
    
	public void setGroups(Set<Group> groups) {
		this.groups = groups;
	}

	public void setId(String id) {
		this.id = id;
	}

	public void setListDepartment(List<Department> listDepartment) {
		this.listDepartment = listDepartment;
	}

	public void setListGrp(List<Group> listGrp) {
		this.listGrp = listGrp;
	}


	public void setLstgroups(List<String> lstgroups) {
		this.lstgroups = lstgroups;
	}

	public void setMgr(UserManager mgr) {
		this.mgr = mgr;
	}


	public void setNewlstgroups(List<String> newlstgroups) {
		this.newlstgroups = newlstgroups;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	@Autowired
	public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
		this.passwordEncoder = passwordEncoder;
	}

	public void setPositionId(String positionId) {
		this.positionId = positionId;
	}

	@Autowired
	public void setPositionManager(PositionManager positionManager) {
		this.positionManager = positionManager;
	}
	
	public void setSearch(String search) {
		this.search = search;
	}

	public void setUser(User user) {
		this.user = user;
	}

	public void setUserManager(UserManager userManager) {
        this.mgr = userManager;
    }

	public void setUsers(List<User> users) {
		this.users = users;
	}

	@Override
	public void validate() {
 	    if ((user.getId() == null) || !(user.getUsername().equals(mgr.get(user.getId()).getUsername()))) {
 	    	if (!StringUtils.isEmpty(user.getUsername())) {	
 	    		users = mgr.searchByUserName(user.getUsername());
 	    			if (users.size()>0)
 	    				addActionError(getText("user.error.username.not.valid"));
 	    	}
	    }
	}
}
